package com.sloan.community.service;

import com.aliyun.oss.OSSClient;
import com.sloan.community.common.res.Result;
import com.sloan.community.common.vo.FileVO;
import com.sloan.community.common.vo.VideoVo;
import com.sloan.community.config.AliyunOssProperties;
import com.sloan.community.exception.CommunityException;
import com.sloan.community.util.ImageVideoUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.io.*;
import java.util.UUID;


@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
public class FileService {

    private final OSSClient ossClient;

    private final AliyunOssProperties properties;

    public Mono<Result<FileVO>> upload(FilePart filePart) {
        return Mono.just(filePart)
                .map(file -> ImageVideoUtils.getFileExtension(filePart.filename()))
                .switchIfEmpty(Mono.error(CommunityException.of("上传文件出现问题!")))
                .then(DataBufferUtils.join(filePart.content())
                        .map(dataBuffer -> {
                            InputStream inputStream = dataBuffer.asInputStream();
                            DataBufferUtils.release(dataBuffer); // 释放资源
                            String newFileName = UUID.randomUUID() + "." + ImageVideoUtils.getFileExtension(filePart.filename());
                            String baseUrl = ImageVideoUtils.uploadPath("article") + newFileName;
                            ossClient.putObject(properties.getBucketName(), baseUrl, inputStream);
                            String urlPrefix = "https://" + properties.getBucketName() + "." + properties.getEndpoint() + "/";
                            return Result.success(new FileVO(filePart.filename(), newFileName, urlPrefix + baseUrl));
                        }))
                .doOnError(err -> {
                    log.error("上传文件出错:{}", err.getMessage());
                })
                .onErrorResume(err -> Mono.error(CommunityException.of(err.getMessage())));
    }


    public Mono<Result<VideoVo>> uploadVideo(FilePart filePart) {
        return Mono.just(filePart)
                .map(file -> ImageVideoUtils.getFileExtension(filePart.filename()))
                .switchIfEmpty(Mono.error(CommunityException.of("上传视频文件出现问题!")))
                .then(DataBufferUtils.join(filePart.content())
                        .map(dataBuffer -> {
                            InputStream inputStream = dataBuffer.asInputStream();
                            // 释放资源
                            DataBufferUtils.release(dataBuffer);

                            String urlPrefix = "https://" + properties.getBucketName() + "." + properties.getEndpoint() + "/";
                            String upLoadDir = ImageVideoUtils.uploadPath("video");
                            String fileName = UUID.randomUUID() + ".";
                            String newFileName = fileName + ImageVideoUtils.getFileExtension(filePart.filename());
                            String baseUrl = upLoadDir + newFileName;
                            ossClient.putObject(properties.getBucketName(), baseUrl, inputStream);

                            String videoUrl = urlPrefix + baseUrl;
                            log.info("生成的视频文件地址:{}", videoUrl);

                            // 将 DataBufferInputStream 中的数据写入临时文件
                            ByteArrayInputStream firstFrameStream = ImageVideoUtils.getFirstFrame(writeTempFile(dataBuffer), 1);
                            String firstFrameImgUrl = upLoadDir + fileName + ImageVideoUtils.FILE_EXT;
                            ossClient.putObject(properties.getBucketName(), firstFrameImgUrl, firstFrameStream);
                            log.info("生成的第一帧照片:{}", firstFrameImgUrl);
                            return Result.success(new VideoVo(filePart.filename(), newFileName, urlPrefix + baseUrl, urlPrefix + firstFrameImgUrl));
                        }))
                .doOnError(err -> {
                    log.error("上传文件出错:{}", err.getMessage());
                })
                .onErrorResume(err -> Mono.error(CommunityException.of(err.getMessage())));
    }

    // TODO 暂时写写入临时文件，后面在优化
    public FileInputStream writeTempFile(DataBuffer dataBuffer) {
        File tempFile;
        FileOutputStream fileOutputStream = null;
        try {
            tempFile = File.createTempFile("temp-ysj", ".mp4");
            fileOutputStream = new FileOutputStream(tempFile);
            fileOutputStream.write(dataBuffer.asByteBuffer().array());
            FileInputStream fileInputStream = new FileInputStream(tempFile);
            if (tempFile.exists()) {
                tempFile.delete();
            }
            return fileInputStream;
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                fileOutputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
